﻿#region License
// (c) Intergen.
// This source is subject to the Microsoft Public License (Ms-PL).
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.
#endregion

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Browser;
using System.Windows.Interop;
using System.Net;
using TextGlow.Control.Controls;
using TextGlow.Control.Packaging;
using TextGlow.Control.Model;
using System.Reflection;
using TextGlow.Control.Controls.Document;
using TextGlow.Control.UI;

namespace TextGlow.Control
{
  [ScriptableType]
  public partial class Page : UserControl
  {
    private WebClient _downloader;
    private Uri _documentPath;
    private Uri _baseUri;

    public Uri DocumentPath
    {
      get { return _documentPath; }
      set { _documentPath = value; }
    }
    
    public Page()
    {
      InitializeComponent();

      SetContainerSize();

      SilverlightHost host = Application.Current.Host;

      host.Content.Resized += new EventHandler(Resized);
      host.Content.FullScreenChanged += new EventHandler(Resized);
      Loaded += new RoutedEventHandler(PageLoaded);

      Uri documentUri = HtmlPage.Document.DocumentUri;

      string baseUri = documentUri.ToString().Substring(0, documentUri.ToString().LastIndexOf("/") + 1);
      _baseUri = new Uri(baseUri, UriKind.Absolute);
    }

    [ScriptableMember]
    public void SetDocument(string documentUri)
    {
      SetDocument(new Uri(documentUri, UriKind.Relative));
    }

    public void SetDocument(Uri documentUri)
    {
      Uri newDocumentPath;

      if (documentUri.IsAbsoluteUri)
        newDocumentPath = documentUri;
      else
        newDocumentPath = new Uri(_baseUri, documentUri);

      if (newDocumentPath != _documentPath)
      {
        _documentPath = newDocumentPath;

        Container.ClearPages();
        Container.SetDocumentUriText(_documentPath);
        Container.SetProgress(0);
        Container.SetProgressLabel("Downloading " + _documentPath);
        Container.ShowProgressPanel();

        if (_downloader != null)
        {
          _downloader.DownloadProgressChanged -= DownloadProgressChanged;
          _downloader.OpenReadCompleted -= _downloader_OpenReadCompleted;
          _downloader.CancelAsync();
        }

        _downloader = new WebClient();
        _downloader.DownloadProgressChanged += DownloadProgressChanged;
        _downloader.OpenReadCompleted += _downloader_OpenReadCompleted;
        _downloader.OpenReadAsync(_documentPath);
      }
    }

    private void DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
    {
      Container.SetProgress(e.ProgressPercentage);
    }

    private void PageLoaded(object sender, RoutedEventArgs e)
    {
      HtmlPage.RegisterScriptableObject("TextGlow", this);

      Container.FullScreenButtonClick += FullScreenButtonClick;
      Container.SaveButtonClick += SaveButtonClick;
      Container.CoverClick += Container_CoverClick;
      Container.PreviousPageButtonClick += PreviousPageButtonClick;
      Container.NextPageButtonClick += NextPageButtonClick;
      Container.ProgressHidden += ProgressHidden;

      SetContainerSize();

      if (_documentPath != null)
        SetDocument(_documentPath);
    }

    private void SaveButtonClick(object sender, EventArgs e)
    {
      if (_documentPath != null)
      {
        Uri pageUri = HtmlPage.Document.DocumentUri;
        Uri documentUri = new Uri(pageUri, _documentPath);

        HtmlPage.Window.Navigate(documentUri);
      }
    }

    private void PreviousPageButtonClick(object sender, EventArgs e)
    {
      if (Container.CurrentPageIndex - 1 >= 0)
        Container.SelectCover(Container.CurrentPageIndex - 1);
    }

    private void NextPageButtonClick(object sender, EventArgs e)
    {
      if (Container.CurrentPageIndex + 1 < Container.PageCount)
        Container.SelectCover(Container.CurrentPageIndex + 1);
    }

    void Container_CoverClick(object sender, EventArgs e)
    {
      PageCover clickedCover = (PageCover)sender;
      Container.SelectCover(Convert.ToInt32(clickedCover.Name.Split('_')[1]));
    }

    private void FullScreenButtonClick(object sender, EventArgs e)
    {
      Application.Current.Host.Content.IsFullScreen = !Application.Current.Host.Content.IsFullScreen;
    }

    private void Resized(object sender, EventArgs e)
    {
      if (Application.Current.Host.Content.ActualWidth > 0 && Application.Current.Host.Content.ActualHeight > 0)
      {
        SetContainerSize();
      }
    }

    private void SetContainerSize()
    {
      SilverlightHost host = Application.Current.Host;

      double actualWidth = (host.Content.ActualWidth > 0) ? host.Content.ActualWidth : 700;
      double actualHeight = (host.Content.ActualHeight > 0) ? host.Content.ActualHeight : 700;

      double desiredWidth = 600;
      double desiredHeight = 700;

      double scale = Math.Min(actualWidth / desiredWidth, actualHeight / desiredHeight);

      Scale.ScaleX = scale;
      Scale.ScaleY = scale;

      Container.Width = actualWidth / scale;
      Container.Height = actualHeight / scale;
      Container.InvalidateArrange();
    }

    void _downloader_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
    {
      if (e.Error == null)
      {
        try
        {
          Container.SetProgressLabel("Loading " + _documentPath.ToString());
          Container.UpdateLayout();

          Stream packageStream = e.Result;

          IContentGetter contentGetter = new PackageContentGetter(packageStream);
          Package package = new Package(contentGetter);
          Document documentModel = Document.CreateDocument(package);

          DocumentBuilder documentBuilder = new DocumentBuilder(documentModel, p => Container.AddPage(p));
          documentBuilder.BuildDocument();

          _downloader = null;
          Container.HideProgressPanel();
        }
        catch (Exception ex)
        {
          if (ex is TargetInvocationException)
            ex = ex.InnerException;

          Container.SetProgressLabel(ex.Message);
        }
      }
      else
      {
        Container.SetProgressLabel(e.Error.Message);
      }
    }

    private void ProgressHidden(object sender, EventArgs e)
    {
      Container.ShowPages();
    }
  }
}
